/**
 * @file      ICM20948.h
 * @brief     ICM-20948 9轴运动跟踪设备驱动程序
 * @version   1.0
 * @date      2025-07-15
 * @note      本驱动基于TDK ICM-20948数据手册 (DS-000189, rev 1.6)
 */

#ifndef ICM20948_H
#define ICM20948_H

#include <stdint.h>
#include <stdbool.h>
#include "ti_msp_dl_config.h"

/*************************************************************************************************/
/*                                         宏定义                                                */
/*************************************************************************************************/

/* 
 * I2C 地址
 * AD0 = 0 -> 0x68
 * AD0 = 1 -> 0x69
 */
#define ICM20948_I2C_ADDR_AD0_LOW    0x68
#define ICM20948_I2C_ADDR_AD0_HIGH   0x69
#define ICM20948_I2C_ADDR            ICM20948_I2C_ADDR_AD0_LOW // AD0接地

/* 磁力计 (AK09916) I2C 地址 */
#define AK09916_I2C_ADDR             0x0C

/* 设备ID */
#define ICM20948_DEVICE_ID           0xEA
#define AK09916_DEVICE_ID            0x09 // 公司ID为0x48, 设备ID为0x09

/* 用户Bank选择 */
#define REG_BANK_SEL                 0x7F
#define USER_BANK_0                  0x00
#define USER_BANK_1                  0x10
#define USER_BANK_2                  0x20
#define USER_BANK_3                  0x30


/*************************************************************************************************/
/*                                     用户Bank 0 寄存器                                         */
/*************************************************************************************************/
#define WHO_AM_I_ICM20948            0x00
#define USER_CTRL                    0x03
#define LP_CONFIG                    0x05
#define PWR_MGMT_1                   0x06
#define PWR_MGMT_2                   0x07
#define INT_PIN_CFG                  0x0F
#define INT_ENABLE                   0x10
#define INT_ENABLE_1                 0x11
#define INT_ENABLE_2                 0x12
#define INT_ENABLE_3                 0x13
#define I2C_MST_STATUS               0x17
#define INT_STATUS                   0x19
#define INT_STATUS_1                 0x1A
#define INT_STATUS_2                 0x1B
#define INT_STATUS_3                 0x1C
#define DELAY_TIMEH                  0x28
#define DELAY_TIMEL                  0x29
#define ACCEL_XOUT_H                 0x2D
#define ACCEL_XOUT_L                 0x2E
#define ACCEL_YOUT_H                 0x2F
#define ACCEL_YOUT_L                 0x30
#define ACCEL_ZOUT_H                 0x31
#define ACCEL_ZOUT_L                 0x32
#define GYRO_XOUT_H                  0x33
#define GYRO_XOUT_L                  0x34
#define GYRO_YOUT_H                  0x35
#define GYRO_YOUT_L                  0x36
#define GYRO_ZOUT_H                  0x37
#define GYRO_ZOUT_L                  0x38
#define TEMP_OUT_H                   0x39
#define TEMP_OUT_L                   0x3A
#define EXT_SLV_SENS_DATA_00         0x3B
// ... up to EXT_SLV_SENS_DATA_23

/*************************************************************************************************/
/*                                     用户Bank 1 寄存器                                         */
/*************************************************************************************************/
#define SELF_TEST_X_GYRO             0x02
#define SELF_TEST_Y_GYRO             0x03
#define SELF_TEST_Z_GYRO             0x04
#define SELF_TEST_X_ACCEL            0x0E
#define SELF_TEST_Y_ACCEL            0x0F
#define SELF_TEST_Z_ACCEL            0x10
#define XA_OFFS_H                    0x14
#define XA_OFFS_L                    0x15
#define YA_OFFS_H                    0x17
#define YA_OFFS_L                    0x18
#define ZA_OFFS_H                    0x1A
#define ZA_OFFS_L                    0x1B
#define TIMEBASE_CORRECTION_PLL      0x28

/*************************************************************************************************/
/*                                     用户Bank 2 寄存器                                         */
/*************************************************************************************************/
#define GYRO_SMPLRT_DIV              0x00
#define GYRO_CONFIG_1                0x01
#define GYRO_CONFIG_2                0x02
#define ACCEL_SMPLRT_DIV_1           0x10
#define ACCEL_SMPLRT_DIV_2           0x11
#define ACCEL_INTEL_CTRL             0x12
#define ACCEL_WOM_THR                0x13
#define ACCEL_CONFIG                 0x14
#define ACCEL_CONFIG_2               0x15

/*************************************************************************************************/
/*                                     用户Bank 3 寄存器 (I2C主机)                               */
/*************************************************************************************************/
#define I2C_MST_CTRL                 0x01
#define I2C_MST_DELAY_CTRL           0x02
#define I2C_SLV0_ADDR                0x03
#define I2C_SLV0_REG                 0x04
#define I2C_SLV0_CTRL                0x05
#define I2C_SLV0_DO                  0x06
#define I2C_SLV1_ADDR                0x07
#define I2C_SLV1_REG                 0x08
#define I2C_SLV1_CTRL                0x09
#define I2C_SLV1_DO                  0x0A
// ...

/*************************************************************************************************/
/*                                     磁力计 (AK09916) 寄存器                                   */
/*************************************************************************************************/
#define AK09916_WIA1                 0x00 // Company ID
#define AK09916_WIA2                 0x01 // Device ID
#define AK09916_ST1                  0x10 // Status 1
#define AK09916_HXL                  0x11 // X-axis data LSB
#define AK09916_HXH                  0x12 // X-axis data MSB
#define AK09916_HYL                  0x13 // Y-axis data LSB
#define AK09916_HYH                  0x14 // Y-axis data MSB
#define AK09916_HZL                  0x15 // Z-axis data LSB
#define AK09916_HZH                  0x16 // Z-axis data MSB
#define AK09916_ST2                  0x18 // Status 2
#define AK09916_CNTL2                0x31 // Control 2
#define AK09916_CNTL3                0x32 // Control 3

/*************************************************************************************************/
/*                                         配置位定义                                            */
/*************************************************************************************************/

// PWR_MGMT_1
#define PWR_MGMT_1_DEVICE_RESET_BIT  7
#define PWR_MGMT_1_SLEEP_BIT         6
#define PWR_MGMT_1_CLKSEL_BITS       0
#define PWR_MGMT_1_CLK_BEST_AVAIL    1 // 推荐选择：自动选择最佳可用时钟源

// USER_CTRL
#define USER_CTRL_I2C_MST_EN_BIT     5
#define USER_CTRL_DMP_EN_BIT         7

// ACCEL_CONFIG
#define ACCEL_FS_SEL_2G              (0 << 1)
#define ACCEL_FS_SEL_4G              (1 << 1)
#define ACCEL_FS_SEL_8G              (2 << 1)
#define ACCEL_FS_SEL_16G             (3 << 1)

// GYRO_CONFIG_1
#define GYRO_FS_SEL_250DPS           (0 << 1)
#define GYRO_FS_SEL_500DPS           (1 << 1)
#define GYRO_FS_SEL_1000DPS          (2 << 1)
#define GYRO_FS_SEL_2000DPS          (3 << 1)

// AK09916_CNTL2
#define AK09916_MODE_POWER_DOWN      0x00
#define AK09916_MODE_SINGLE          0x01
#define AK09916_MODE_CONT_10HZ       0x02
#define AK09916_MODE_CONT_20HZ       0x04
#define AK09916_MODE_CONT_50HZ       0x06
#define AK09916_MODE_CONT_100HZ      0x08
#define AK09916_MODE_SELF_TEST       0x10

/*************************************************************************************************/
/*                                         数据结构定义                                          */
/*************************************************************************************************/

/**
 * @brief ICM20948 原始数据结构体
 */
typedef struct {
    int16_t accel_x;
    int16_t accel_y;
    int16_t accel_z;
    int16_t gyro_x;
    int16_t gyro_y;
    int16_t gyro_z;
    int16_t mag_x;
    int16_t mag_y;
    int16_t mag_z;
    int16_t temp;
} ICM20948_RawData_t;

/**
 * @brief ICM20948 转换后数据结构体 (单位: g, dps, uT, C)
 */
typedef struct {
    float accel_x_g;
    float accel_y_g;
    float accel_z_g;
    float gyro_x_dps;
    float gyro_y_dps;
    float gyro_z_dps;
    float mag_x_ut;
    float mag_y_ut;
    float mag_z_ut;
    float temp_c;
    uint32_t timestamp;
} ICM20948_Data_t;

/**
 * @brief 加速度计满量程范围
 */
typedef enum {
    ACCEL_FS_2G = 0,
    ACCEL_FS_4G,
    ACCEL_FS_8G,
    ACCEL_FS_16G
} ICM20948_AccelFSR_t;

/**
 * @brief 陀螺仪满量程范围
 */
typedef enum {
    GYRO_FS_250DPS = 0,
    GYRO_FS_500DPS,
    GYRO_FS_1000DPS,
    GYRO_FS_2000DPS
} ICM20948_GyroFSR_t;

/**
 * @brief 磁力计测量模式
 */
typedef enum {
    MAG_MODE_POWER_DOWN = 0,
    MAG_MODE_SINGLE,
    MAG_MODE_CONT_10HZ,
    MAG_MODE_CONT_20HZ,
    MAG_MODE_CONT_50HZ,
    MAG_MODE_CONT_100HZ
} ICM20948_MagMode_t;


/*************************************************************************************************/
/*                                         函数声明                                              */
/*************************************************************************************************/

/**
 * @brief 初始化ICM20948传感器
 * @return 0: 成功, -1: 失败
 */
int8_t ICM20948_Init(void);

/**
 * @brief 检查设备ID
 * @return 0: 成功, -1: 失败
 */
int8_t ICM20948_CheckID(void);

/**
 * @brief 软复位ICM20948
 */
void ICM20948_Reset(void);

/**
 * @brief 唤醒ICM20948
 */
void ICM20948_WakeUp(void);

/**
 * @brief 设置加速度计满量程范围
 * @param fsr 满量程范围
 */
void ICM20948_SetAccelFSR(ICM20948_AccelFSR_t fsr);

/**
 * @brief 设置陀螺仪满量程范围
 * @param fsr 满量程范围
 */
void ICM20948_SetGyroFSR(ICM20948_GyroFSR_t fsr);

/**
 * @brief 设置加速度计采样率分频
 * @param div 分频值 (0-4095)
 */
void ICM20948_SetAccelSampleRateDiv(uint16_t div);

/**
 * @brief 设置陀螺仪采样率分频
 * @param div 分频值 (0-255)
 */
void ICM20948_SetGyroSampleRateDiv(uint8_t div);

/**
 * @brief 初始化磁力计 (AK09916)
 * @param mode 测量模式
 * @return 0: 成功, -1: 失败
 */
int8_t ICM20948_MagInit(ICM20948_MagMode_t mode);

/**
 * @brief 检查磁力计ID
 * @return 0: 成功, -1: 失败
 */
int8_t ICM20948_CheckMagID(void);

/**
 * @brief 读取所有传感器原始数据
 * @param data 存储原始数据的结构体指针
 */
void ICM20948_ReadRawData(ICM20948_RawData_t *data);

/**
 * @brief 读取所有传感器数据并进行单位转换
 * @param data 存储转换后数据的结构体指针
 */
void ICM20948_ReadData(ICM20948_Data_t *data);

/**
 * @brief 数据就绪(DRDY)中断处理函数
 */
void ICM20948_DRDY_Handler(void);

/**
 * @brief 判断ICM20948是否数据就绪
 * @return true: 数据就绪, false: 数据未就绪
 */
bool ICM20948_IsDataReady(void);

/**
 * @brief 切换ICM20948的用户Bank
 * @param bank 要切换的Bank (USER_BANK_0, USER_BANK_1, USER_BANK_2, USER_BANK_3)
 * @return 0: 成功, -1: 失败
 */
int8_t ICM20948_SwitchBank(uint8_t bank);

/**
 * @brief 读单个寄存器
 * @param reg 寄存器地址
 * @param value 读取值存储位置
 * @return 0: 成功, -1: 失败
 */
int8_t ICM20948_ReadReg(uint8_t reg, uint8_t* value);

/**
 * @brief 写单个寄存器
 * @param reg 寄存器地址
 * @param value 要写入的值
 * @return 0: 成功, -1: 失败
 */
int8_t ICM20948_WriteReg(uint8_t reg, uint8_t value);

/**
 * @brief 读多个寄存器
 * @param reg 起始寄存器地址
 * @param buffer 读取值存储缓冲区
 * @param length 要读取的字节数
 * @return 0: 成功, -1: 失败
 */
int8_t ICM20948_ReadMultipleRegs(uint8_t reg, uint8_t* buffer, uint8_t length);

/**
 * @brief 向DMP程序内存写入数据
 * @param memory_addr 内存地址
 * @param data 数据缓冲区
 * @param size 数据大小(字节)
 * @return 0: 成功, 非0: 错误代码
 * @note 此函数用于DMP固件加载
 */
int8_t ICM20948_WriteMemory(uint16_t memory_addr, const uint8_t *data, uint16_t size);

/**
 * @brief 从DMP程序内存读取数据
 * @param memory_addr 内存地址
 * @param data 数据缓冲区
 * @param size 数据大小(字节)
 * @return 0: 成功, 非0: 错误代码
 */
int8_t ICM20948_ReadMemory(uint16_t memory_addr, uint8_t *data, uint16_t size);

#endif /* ICM20948_H */ 